Jenkins 下UE4 iOS 签名证书自动配置方法

您所在的位置:网站首页 ue4 ios打包 Jenkins 下UE4 iOS 签名证书自动配置方法

Jenkins 下UE4 iOS 签名证书自动配置方法

#Jenkins 下UE4 iOS 签名证书自动配置方法| 来源: 网络整理| 查看: 265

(题图来源于:Keychain Access MacOS Xcode Dialog Box Electronics Accessory PNG - Free Download)

前言

近期正好处理了一下项目的 iOS 打包流程,将之前并不清晰的流程梳理了一下。其中老项目中遗漏的最复杂的一个问题就是关于 macOS 下进行版本签名的处理方式,这次借这个机会终于将其解决掉了,特此在这篇文章中记录一下,希望以后的人可以参考,少走弯路。

阅读本文需要如下前提知识:

Jenkins 管理知识:Jenkins Slave 连接方法,Credential 管理及配置方法iOS 版本构建及签名知识:知道 Provision 和 Certification,知道 macOS KeychainUE4 iOS 版本打包流程及打包方法一定的 macOS/Linux 命令行使用经验及SSH 使用经验

基本上做过在 macOS 下使用 Jenkins 进行过UE4 iOS 构建的人都能够掌握,如果你还没有遇到过关于iOS签名的问题,可能这篇文章对你的帮助并不大。

传统方案

先简单介绍一下大致UE4下 iOS版本签名原理以及之前项目中使用的传统方案。

签名原理

iOS App 在签名的过程中,主要涉及到两个文件,一是 Provision 文件,二是证书文件(P12)。 Provision 文件相对比较简单,只要复制到对应的目录(一般是 ~/Library/MobileDevice/Provisioning Profiles)即可。证书文件使用起来相对复杂一些,需要将证书文件导入到登录钥匙串(Login Keychain)。如果只是使用 Xcode 开发 iOS App 还方便一些,因为 Xcode 帮忙隐藏掉了大部分的问题,但是在 UE4 下通过 UAT 进行签名时,就会发现经常遇到让人挠头的 codesign errSecInternalComponent 问题。

这个问题在 Apple 官方没有详细的说明,一般来说出现 errSecInternalComponent 问题表示当前运行 codesign 时,证书权限出现了一些问题,这些问题基本可以分为以下几个类别:

登录Session不匹配当前 Keychain 的 Search List 中没有需要使用的证书文件Keychain 没有解锁codesign 没有使用证书进行签名的权限方案介绍

在之前的项目中,由于当时对整个流程认识有限,使用的方案比较简单手工操作较多,并不能实现全部的自动化配置。当时主要配置方法如下(分别对应上述的几个问题):

Mac 系统使用桌面上的 Jenkins Agent 方式连接到 Jenkins,没有使用 SSH 连接;手动将 P12 证书文件导入到 Login Keychain;注意不要锁定登录钥匙串,也不要开启登录钥匙串自动锁定功能;在钥匙串访问中,双击导入的证书,点开“信任”字段,在“代码签名”一项中选择总是信任。或者在第一次使用新导入的证书进行签名时,在弹出的证书信任对话框中,选择“总是信任”。

按照上述方法设置的证书可以正常应用在UE4打包流程中,一般不会遇到证书相关的问题。如果依然出现了证书问题,请再次确认上述配置方法是否一致,并尝试使用 codesign 命令手动签名,codesign命令的具体参数可以在 UE4 Log 中找到。

新方法研究动机

虽然传统方法可以达到 iOS 自动化打包的目的,然而很多步骤都需要手工处理总是一块心病,所以根据之前的方法,总结了一下需要研究解决的问题:

UE4的iOS签名过程属于其 Packaging 的一部分,在 RunUAT 的 BuildCookRun 环节的最后就会自动进行版本签名。如果此时签名出现问题,整个流程就会认为失败,所以不可以将前签名环节移动到 Packaging 以后再进行处理;减少编译机的手动配置流程,尽量在 Jenkins Job 中自动化配置,这也就要求不能在编辑机上预先导入签名用的 p12 证书文件。当编译机较多时,这一点非常重要,避免了每次需要更新证书时的手动操作,而且也可以避免由此而来的问题;降低 Jenkins Job 对宿主机的影响,应当做到在 Job 运行结束后,除了 Jenkins workspace 以外不会对宿主机做任何的修改。当多任务共享编译机时,保持宿主机干净有序是个重要的问题,一是避免对不相干的任务产生影响;二是可以避免证书滥用的问题;所有使用的密码都通过 Jenkins Credential 管理,最大程度上避免密码泄露。自动化方案介绍使用SSH

首先第一步就是使用 SSH 连接 Jenkins Slave,避免使用在 Mac 下运行 Jenkins Slave Agent 的方式。这样的好处是可以避免手动在 Mac 下配置 Slave 相关的环境,并且在编译机重新启动以后,可以由 Jenkins Master 自动连接 Slave,不需要手动登录到 Mac 桌面环境。这方面的配置在网上介绍的已经非常详细了(可以参考文章最后的参考2连接),这里不再赘述。

创建临时Keychain

为了达到尽量不污染宿主机的目的,所以建议使用临时 Keychain 的方案来保存导入的证书,在使用完毕以后,将整个 Keychain 进行删除。

创建 Keychain 的方法是:

security create-keychain -p $TEMP_KEYCHAIN_PASSWORD $TEMP_KEYCHAIN_NAME

注: 在本文中,以$开头的大写字母表示需要配置的参数,一般通过参数名称即可知道其语义,如果前后命令使用了相同的参数名,表示需要使用相同的值。在实际使用中,请根据情况替换为文本或者其他类型的参数。本文后面会使用相同风格的写法,不再重复说明。

下面简单介绍一下使用的参数:

TEMP_KEYCHAIN_PASSWORD 表示以后访问或者解锁这个 Keychain 时,需要提供的密码。TEMP_KEYCHAIN_NAME 表示创建的 Keychain 名称,一般使用 XXX.keychain 的形式,例如 Temp.keychain,创建以后,会在 ~/Library/Keychains 下创建一个叫做 Temp.keychain-db 的文件。

当使用完毕后,可以通过如下命令删除临时 Keychain,如果使用 Jenkins Pipeline 的话,可以写在 cleanup stage 里面 :

security delete-keychain $TEMP_KEYCHAIN_NAME导入证书

使用如下命令导入 P12 文件到 Keychain:

security import $CERT_FILE_PATH -k $TEMP_KEYCHAIN_NAME -P $CERT_PASSPHRASE -T /usr/bin/codesign

其中:

$CERT_FILE_PATH 表示 P12 文件的路径,可以使用相对路径或者绝对路径$CERT_PASSPHRASE 表示 P12 证书的密码-T /usr/bin/codesign 表示信任 /usr/bin/codesign 命令,在第一次使用的时候,就不会弹出“是否信任”的对话框了(注:在 macOS Sierra 及以后的版本中,仅仅使用这一个参数已经不能解决弹出对话框的问题,请参考文章后续内容)。Keychain Partition List 设置

从 macOS Sierra 开始,Apple 使用了新的 Keychain 管理策略 Partition List,然而并没有什么公开的资料来说明修改以后的使用方法,通过查阅网上的各种资料,基本使用方法总如下:

security set-key-partition-list -S apple-tool:,apple: -s -k $TEMP_KEYCHAIN_PASSWORD $TEMP_KEYCHAIN_NAME

简单解释一下这个命令:

Partition List 是类似于访问控制列表(ACL)的一种管理策略, 需要显式设置 Keychain 中哪些项目可以被哪些应用所访问,这也就解释了为什么前面在导入证书时,只使用 -T 指定 codesign 命令不再生效的原因。-S 表示逗号分隔的允许的 Partition ID,这个 Partition ID 在官方也没有得到解释,不过在参考5 和 参考6 中提到了可以使用 security dump-keychain -a 的方式打印 keychain 中已有的 Partition ID 来参考。如果希望得到某个应用的 Partition ID,可以采用先 dump-keychain 然后启动应用,在弹出的信任对话框中选择“总是信任”以后,再次 dump-keychain,比较两次结果的差异来获得。不过对于签名应用来说,并不需要这么复杂的处理,使用上面命令中的两个 Partition ID 就足够了。在一些文章中使用到了 -D 参数,可以匹配到 Keychain 中特定的项目,在当前的应用中,因为创建的临时 Keychain 中只有这一个证书,所以将整个 Keychain 中的项目都设置 Partition List 就可以了。Keychain Search List 设置

当创建了 Keychain 并导入证书以后,此时如果使用 security find-identity 查找证书的话,其实是无法找到刚刚导入的证书的。原因是新创建的 Keychain 并没有在搜索路径中,需要手动将新创建的 Keychain 加入到搜索路径中:

security list-keychains -s `security list-keychains | xargs` $TEMP_KEYCHAIN_NAME

其中 security list-keychains | xargs 是为了已经在搜索路径中的 Keychain 也加入到新的搜索路径中,-s 参数只能设置搜索路径,并不能增量添加。

在某些文章中使用了:

security default-keychains -s $TEMP_KEYCHAIN_NAME

来设置默认 Keychain,我个人认为这样做有些问题,因为会覆盖掉原来搜索路径设置,在任务结束以后不好恢复到初始状态。而且使用 list-keychains 设置的搜索路径,在删除掉临时 Keychain 以后,会自动恢复为原始的搜索路径,会比较方便。

其他设置(可选)

创建 Keychain 后,可以设置一下 keychain 的超时自动锁定时间:

security set-keychain-settings -t 3600 $TEMP_KEYCHAIN_NAME

其中 3600 表示超过 3600 秒以后自动锁定Keychain。

在实际使用 Keychain 之前,可以先解锁一下 Keychain,避免由于某种特殊原因系统将其锁定:

security unlock-keychain -p $TEMP_KEYCHAIN_PASSWORD $TEMP_KEYCHAIN_NAME特殊问题处理

如果所有的设置都已经完成了,依然遇到权限问题,那么可以检查一下在系统中是否有且只有唯一的证书用于签名:

security find-identity -vp codesigning

解释一下参数:

find-identity 表示在 Search List 中查找符合指定要求的项目-v 表示只显示可用的项目,隐藏不可用的项目-p codesigning 表示查找用于代码签名的项目

如果本机只有单独一个用于签名的证书,那么这个命令应当只返回唯一的结果;如果本机有多个用于签名的证书,那么应当会返回多个不同的结果。我遇到的一个问题是,这个命令返回了多个相同的结果,猜测与我之前将证书导入到 Login Keychain 有关系。如果遇到了和我一样的问题,那么手动到钥匙串访问中,删除所有相关的证书以及专用秘钥(如下图所示的两项内容),然后再重新进行导入到临时 Keychain。

最终 Pipeline 示例

上面写的比较分散,在这里贴一部分相关的 Pipeline 代码,用于最终参考:

pipeline { stages { stage('Code Sign') { steps { sh """ # Create Temp Keychain and Import security create-keychain -p $TEMP_KEYCHAIN_PASSWORD $TEMP_KEYCHAIN_NAME security import $CERT_FILE_PATH -k $TEMP_KEYCHAIN_NAME -P $CERT_PASSPHRASE -T /usr/bin/codesign # Set Partition List security set-key-partition-list -S apple-tool:,apple: -s -k $TEMP_KEYCHAIN_PASSWORD $TEMP_KEYCHAIN_NAME # Set Search List security list-keychains -s `security list-keychains | xargs` $TEMP_KEYCHAIN_NAME # Other Settings security set-keychain-settings -t 3600 $TEMP_KEYCHAIN_NAME security unlock-keychain -p $TEMP_KEYCHAIN_PASSWORD $TEMP_KEYCHAIN_NAME # Show Identities security find-identity -vp codesigning # Do your own work here """ } } } post { cleanup { sh """ # Remove Temp Keychain security delete-keychain $TEMP_KEYCHAIN_NAME || true """ } } }

注意上述代码中有很多变量需要定义,仅用于参考,不可直接使用。

关于 WWDR 证书的说明

(2021年11月22日更新,感谢 @RakuBun 提供的信息)

如果配置都没有问题,然而在 codesign 时还是出现的证书相关的错误,那么请注意是否是 WWDR(Apple Worldwide Developer Relationship)证书过期的问题。Apple 在 2021年1月28日起启用新的根证书来签发开发者证书,所以如果你的证书是在这个日期以后签发的,一定要使用新的根证书。可以点击这里直接下载,或者访问Apple 关于这个问题的说明页面。另外,也可以参考UDN上王弥曾经回答过的类似问题。

参考How to Fix iOS Application Code Signing Error? 这篇文章给我的帮助最大,所以放到第一位jenkins上新增一个Mac的slave-agentUnable to unlock login keychain on sierra in ssh 我找到的第一篇关于 Partition List 相关的 [Resolved] Codesign error over SSH on macOS 10.12+ 优秀的文章,建议参考,特别是文章中给出的脚本连接。security tool reference security 指令的参考手册Scripting the macOS Keychain - Partition IDs 关于 Partition ID 的探讨和尝试security add-keychain Apple 官方论坛,然而也没有解答How to install developer certificate/private key and provisioning profile for iOS development via command line?Tackling keychain problems in Terminal 关于 Search List 的一些说明Add a keychain to search list? 另一个添加 Search List 的命令,其实大同小异macos - Attempt to sign "no user interaction" for OSX application with codesign 怎么说呢?如果能直接看到他这篇讨论中的回答,就不用看我这篇文章了。


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3